package com.tabnet.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import com.tabnet.beans.commande.Commande;
import com.tabnet.beans.commande.LigneCommande;
import com.tabnet.beans.produit.Produit;
import com.tabnet.beans.produit.ProduitCMD;
import com.tabnet.dao.DAOException;
import com.tabnet.dao.DAOFactory;
import com.tabnet.dao.DAOLigneCommande;
import com.tabnet.dao.DAOProduit;
import com.tabnet.dao.DAOProduitCMD;
import com.tabnet.dao.DAOUtilitaire;

public class LigneCommandeDAOImpl implements DAOLigneCommande{

	private static final String SQL_SELECT_LAST		= "SELECT MAX(IDLigne) AS IDLigne FROM LigneCommande WHERE CMD_NUM = ?";
	private static final String SQL_SELECT_BY_ID	= "SELECT IDLigne, CMD_NUM, QteCMD, PRDC_ID "
			+ "FROM LigneCommande WHERE CMD_NUM = ?";
	private static final String SQL_INSERT			= "INSERT INTO LigneCommande VALUES (?, ?, ?, ?)";
	private static final String SQL_UPDATE_MINUS	= "UPDATE LigneCommande SET QteCMD-=? WHERE CMD_NUM=? AND IDLigne=?";
	private static final String SQL_UPDATE_PLUS		= "UPDATE LigneCommande SET QteCMD+=? WHERE CMD_NUM=? AND IDLigne=?";
	private static final String SQL_DELETE			= "DELETE FROM LigneCommande WHERE CMD_NUM=? AND IDLigne=?";
	
	private DAOFactory _DaoFactory;
	private DAOProduitCMD _DaoProduitCMD;
	private DAOProduit _DaoProduit;
	
	public LigneCommandeDAOImpl( DAOFactory pDaoFactory ) {
        this._DaoFactory = pDaoFactory;
        this._DaoProduitCMD = pDaoFactory.getProduitCMDDAO();
        this._DaoProduit = pDaoFactory.getProduitDAO();
    }
	
	/**
     * <p>Fonction map<br />
     * Simple méthode utilitaire permettant de faire la correspondance (le
     * mapping) entre une ligne issue de la table des lignes de commande (un ResultSet) et
     * un bean LigneCommande.</p>
     * @param resultSet : objet ResultSet
     * @throws SQLException
     * @return un objet LigneCommande
     * */
	private LigneCommande map(ResultSet resultSet) throws SQLException {
		LigneCommande oLigneCommande = new LigneCommande();

		oLigneCommande.setId(resultSet.getInt("IDLigne"));
		oLigneCommande.setQteCmd(resultSet.getInt("QteCMD"));
		
		try {
	    	// récupération de la catégorie avec la DAO
			ProduitCMD oProduitCMD = this._DaoFactory.getProduitCMDDAO().foundProduitCMD(resultSet.getInt("PRDC_ID"));
			oLigneCommande.setProduitCmd(oProduitCMD);
		}
		catch (DAOException e) {
			e.printStackTrace();
		}
		
		return oLigneCommande;
	}
	
	/**
     * <p>Fonction getLastIdLigne<br />
     * Retourne le dernier ID d'une ligne commander</p>
     * @param pNumCommande : le numero de la commande
     * @throws SQLException
     * @return int
     * */
    private int getLastIdLigne(String pNumCommande) throws SQLException, DAOException {
		Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet resultSet = null;
        
        int idLigne = 0;

        try {
        	oConnexion = this._DaoFactory.getConnection();
        	
            // récupération des accessoires commandes
        	oPreparedStatement = DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_SELECT_LAST, false, pNumCommande);
            resultSet = oPreparedStatement.executeQuery();
            
            if ( resultSet.next() )
            	idLigne = resultSet.getInt("IDLigne");
        }
        catch ( SQLException e ) {
            throw new DAOException(e);
        }
        finally {
            DAOUtilitaire.fermeturesSilencieuses( resultSet, oPreparedStatement, oConnexion );
        }

        return idLigne;
    }
    
	@Override
	public Map<Integer, LigneCommande> getLigneCommandes(Commande pCommande) throws DAOException {
    	Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet oResultSet = null;
        Map<Integer, LigneCommande> mapLigneCommande = new HashMap<Integer, LigneCommande>();
        LigneCommande oLigneCommande = null;

        try {
        	oConnexion = this._DaoFactory.getConnection();
        	
            // récupération des lignes commandes
        	oPreparedStatement =  DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_SELECT_BY_ID, false, pCommande.getNum());

        	oResultSet = oPreparedStatement.executeQuery();
        	
            while ( oResultSet.next() ) {
            	oLigneCommande = map( oResultSet );
            	oLigneCommande.setCommande(pCommande);
            	mapLigneCommande.put(oLigneCommande.getId(), oLigneCommande);
            }
        }
        catch ( SQLException e ) {
            throw new DAOException( e );
        }
        finally {
            DAOUtilitaire.fermeturesSilencieuses( oResultSet, oPreparedStatement, oConnexion );
        }

        return mapLigneCommande;
	}

	@Override
	public void addLigneCommande(LigneCommande pLigneCommande, Produit pProduit) throws DAOException {
		Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet valeursAutoGenerees = null;
        boolean execUpd = false;
        
        try {
        	oConnexion = this._DaoFactory.getConnection();
            
        	//Contrôle de la quantité
        	if(this._DaoProduit.trouverProduit(pProduit.getRef(), true).get_qteQtock() >= pLigneCommande.getQteCmd()){
	        	
	        	//Décrémentation du nombre de produit disponible
	        	this._DaoProduit.updProduit(pProduit.getRef(), pLigneCommande.getQteCmd(), true);
	        	execUpd = true;  
        		
        		//insertion du produit commander
	        	this._DaoProduitCMD.addProduitCMD(pLigneCommande.getProduitCmd());
	        	
	        	//Incrémentation du dernier ID d'une ligne commande présent dans la base de données
	        	pLigneCommande.setId(this.getLastIdLigne(pLigneCommande.getCommande().getNum()) + 1);
	        	
	            //insertion de la ligne de commande
	            oPreparedStatement = DAOUtilitaire.initialisationRequetePreparee(oConnexion, SQL_INSERT, true,
	            		pLigneCommande.getId(), pLigneCommande.getCommande().getNum(), pLigneCommande.getQteCmd(),
	            		pLigneCommande.getProduitCmd().getId());
	            
	            if ( oPreparedStatement.executeUpdate() == 0 ){
	            	this.updLigneCommande(pLigneCommande, false);
	                throw new DAOException("Échec de la création d'une ligne commande, aucune ligne ajoutée dans la table.");
	            }
        	}
        	else
                throw new DAOException("Echec quantité demandé trop importante.");
        }
        catch (SQLException e) {
        	if(execUpd)
	        	this._DaoProduit.updProduit(pProduit.getRef(), pLigneCommande.getQteCmd(), false);
        	
            throw new DAOException(e);
        }
        finally {
        	 DAOUtilitaire.fermeturesSilencieuses(valeursAutoGenerees, oPreparedStatement, oConnexion);
        }
	}

	@Override
	public void updLigneCommande(LigneCommande pLigneCommande, boolean pMinus) throws DAOException {
		Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet valeursAutoGenerees = null;

        try {
        	oConnexion = this._DaoFactory.getConnection();
        	
        	//mise a jour de la ligne commander
        	if(pMinus)
	        	oPreparedStatement = DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_UPDATE_MINUS, true,
	        			pLigneCommande.getQteCmd(), pLigneCommande.getCommande().getNum(), pLigneCommande.getId());
        	else
            	oPreparedStatement = DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_UPDATE_PLUS, true,
            			pLigneCommande.getQteCmd(), pLigneCommande.getCommande().getNum(), pLigneCommande.getId());
            
        	if ( oPreparedStatement.executeUpdate() == 0 )
                throw new DAOException( "Échec de la mise a jour de la ligne commander, aucune ligne modifiée dans la table." );

        }
        catch ( SQLException e ) {
            throw new DAOException( e );
        }
        finally {
        	 DAOUtilitaire.fermeturesSilencieuses( valeursAutoGenerees, oPreparedStatement, oConnexion );
        }
	}

	@Override
	public void delLigneCommande(LigneCommande pLigneCommande) throws DAOException {
		Connection oConnexion = null;
        PreparedStatement oPreparedStatement = null;
        ResultSet valeursAutoGenerees = null;
        
        try {
        	oConnexion = this._DaoFactory.getConnection();
        	            
            //suppression de la ligne de commande
        	oPreparedStatement = DAOUtilitaire.initialisationRequetePreparee( oConnexion, SQL_DELETE, true,
        			pLigneCommande.getCommande().getNum(), pLigneCommande.getId() );
        	            
            if ( oPreparedStatement.executeUpdate() == 0 )
                throw new DAOException( "Échec de la suppression de la ligne de commande, aucune ligne ajoutée dans la table." );
            
            //suppression du produit commander
        	this._DaoProduitCMD.delProduitCMD(pLigneCommande.getProduitCmd().getId());
            
            this._DaoProduit.updProduit(pLigneCommande.getProduitCmd().getRef(), pLigneCommande.getQteCmd(), false);
        }
        catch ( SQLException e ) {
            throw new DAOException( e );
        }
        finally {
        	 DAOUtilitaire.fermeturesSilencieuses( valeursAutoGenerees, oPreparedStatement, oConnexion );
        }
	}
}
